#include <QUrl>
#include <QThread>
#include <QToolButton>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDebug>
#include <QFileIconProvider>
#include <QFileInfo>
#include <QProcess>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo>

#include <QRoundProgressBar.h>

#include "downloaditem.h"
#include "../filedownloader.h"
#include "../widgets/hovertoolbutton.h"
#include "imageviewer.h"

namespace Jcr
{

class DownloadItemPrivate
{
public:
    DownloadItemPrivate(DownloadItem* q);

    void init();
    void abort();
    void locate();
    void move();
    void view();

    DownloadItem* q_ptr;
    QUrl url;
    QString saveDir;
    QString saveName;
    bool isFinished = false;

    Jcr::FileDownloader* fileDownloader = nullptr;

    QRoundProgressBar* pgsBar = nullptr;

    QLabel* iconLabel;
    QLabel* urlLabel;
    QLabel* localPathLabel;

    QToolButton* abortButton;
    QToolButton* openButton;
    Jcr::HoverToolButton* viewButton;
    QToolButton* moveButton;
};

static const QSize IconSize = QSize(24, 24);

DownloadItemPrivate::DownloadItemPrivate(DownloadItem *q) : q_ptr(q)
{
    init();
}

void DownloadItemPrivate::init()
{
    q_ptr->setMaximumHeight(50);
    q_ptr->setMinimumWidth(300);
    pgsBar = new QRoundProgressBar(q_ptr);
    pgsBar->setValue(0);
    pgsBar->setNullPosition(QRoundProgressBar::PositionRight);
    pgsBar->setBarStyle(QRoundProgressBar::StyleLine);

    iconLabel = new QLabel(q_ptr);
    iconLabel->setMaximumSize(50, 50);

    QHBoxLayout* mainLayout = new QHBoxLayout;

    QVBoxLayout* labelLayout = new QVBoxLayout;
    urlLabel = new QLabel(q_ptr);
    localPathLabel = new QLabel(q_ptr);
    localPathLabel->setAlignment(Qt::AlignRight);
    localPathLabel->setStyleSheet("color:gray;");
    labelLayout->addWidget(urlLabel);
    labelLayout->addWidget(localPathLabel);

    abortButton = new QToolButton(q_ptr);
//    abortButton->setAutoRaise(true);
    abortButton->setIconSize(IconSize);
    abortButton->setIcon(QIcon(":/images/abort.png"));
    abortButton->setToolTip(QObject::tr("Abort downloading"));
    openButton = new QToolButton(q_ptr);
//    openButton->setAutoRaise(true);
    openButton->setIconSize(IconSize);
    openButton->setIcon(QIcon(":/images/open.png"));
    openButton->setToolTip(QObject::tr("Locate file"));
    moveButton = new QToolButton(q_ptr);
//    moveButton->setAutoRaise(true);
    moveButton->setIconSize(IconSize);
    moveButton->setIcon(QIcon(":/images/move.png"));
    moveButton->setToolTip(QObject::tr("Move file"));
    viewButton = new Jcr::HoverToolButton(q_ptr);
    viewButton->setIconSize(IconSize);
//    viewButton->setAutoRaise(true);
    viewButton->setToolTip(QObject::tr("View Image"));

    mainLayout->addWidget(pgsBar);
    mainLayout->addWidget(iconLabel);
    mainLayout->addLayout(labelLayout);
    mainLayout->addStretch();
    mainLayout->addWidget(abortButton);
    mainLayout->addWidget(openButton);
    mainLayout->addWidget(moveButton);
    mainLayout->addWidget(viewButton);
    q_ptr->setLayout(mainLayout);

    openButton->setEnabled(false);
    moveButton->setEnabled(false);
    q_ptr->connect(abortButton, SIGNAL(pressed()), q_ptr, SLOT(onButtonPressed()));
    q_ptr->connect(openButton, SIGNAL(pressed()), q_ptr, SLOT(onButtonPressed()));
    q_ptr->connect(moveButton, SIGNAL(pressed()), q_ptr, SLOT(onButtonPressed()));
    q_ptr->connect(viewButton, SIGNAL(pressed()), q_ptr, SLOT(onButtonPressed()));
}

void DownloadItemPrivate::abort()
{
    fileDownloader->abort();
    pgsBar->setValue(100);
    isFinished = true;
}

void DownloadItemPrivate::locate()
{
    const QString strCmd("explorer.exe");
    const QStringList params = QStringList() << QString("/select,%1").arg(localPathLabel->text());
    QProcess::startDetached(strCmd, params);
}

void DownloadItemPrivate::move()
{
    QString newDir = QFileDialog::getExistingDirectory();
    if (newDir.isEmpty())
        return;

    const QString file = localPathLabel->text();
    QFileInfo fi(file);
    const QString fileName = fi.fileName();
    const QString newFileName = QString("%1/%2").arg(newDir).arg(fileName);

    QFile f(file);
    f.copy(file, newFileName);
    f.remove();
}

void DownloadItemPrivate::view()
{
    // view this image
    const QString imagePath = localPathLabel->text();
    ImageViewer::instance()->view(imagePath);
}

DownloadItem::DownloadItem(QWidget *parent) : QWidget(parent)
{
    d_ptr = new DownloadItemPrivate(this);
}

DownloadItem::DownloadItem(const QUrl& url, QWidget *parent) : QWidget(parent)
{
    d_ptr = new DownloadItemPrivate(this);
    d_ptr->url = url;
}

void DownloadItem::setUrl(const QUrl& url)
{
    if (d_ptr->url != url)
        d_ptr->url = url;
}

QUrl DownloadItem::url() const
{
    return d_ptr->url;
}

void DownloadItem::setSaveDir(const QString& saveDir)
{
    d_ptr->saveDir = saveDir;
}

QString DownloadItem::saveDir() const
{
    return d_ptr->saveDir;
}

void DownloadItem::setSaveName(const QString& name)
{
    d_ptr->saveName = name;
}

QString DownloadItem::saveName() const
{
    return d_ptr->saveName;
}

bool DownloadItem::isFinished() const
{
    return d_ptr->isFinished;
}

void DownloadItem::start()
{
    if (d_ptr->url.isEmpty()) {
        d_ptr->isFinished = true;
        return;
    }

    Jcr::FileDownloader* fd = new Jcr::FileDownloader(this->url());
    d_ptr->fileDownloader = fd;
    fd->setSaveDir(d_ptr->saveDir);
    fd->setSaveName(d_ptr->saveName);

    d_ptr->localPathLabel->setText(fd->localPath());
    d_ptr->urlLabel->setText(d_ptr->url.toString());

    //
    fd->start();
    QThread* thread = new QThread;
    fd->moveToThread(thread);

    connect(thread, SIGNAL(started()), fd, SLOT(start()));
    connect(fd, SIGNAL(finished()), thread, SLOT(terminate()));
    connect(fd, SIGNAL(finished()), this, SLOT(onFinished()));
    connect(fd, SIGNAL(percentCompleted(float)), this, SLOT(onPercentDownloaded(float)));
    connect(fd, SIGNAL(finished()), thread, SLOT(deleteLater()));
    thread->start();
}

void DownloadItem::onFinished()
{
    Jcr::FileDownloader* fd = qobject_cast<Jcr::FileDownloader*>(sender());

    QFileInfo fi(fd->localPath());
    QFileIconProvider fip;
    QIcon icon = fip.icon(fi);
    d_ptr->iconLabel->setPixmap(icon.pixmap(IconSize));

    d_ptr->isFinished = true;
    d_ptr->fileDownloader = nullptr;
    d_ptr->abortButton->setVisible(false);
    d_ptr->openButton->setEnabled(true);
    d_ptr->moveButton->setEnabled(true);

    fd->deleteLater();
}

void DownloadItem::onPercentDownloaded(float percent)
{
    d_ptr->pgsBar->setValue(percent * 100);
}

void DownloadItem::onButtonPressed()
{
    QToolButton* tb = qobject_cast<QToolButton*>(sender());

    if (tb == d_ptr->abortButton && d_ptr->fileDownloader)
        d_ptr->abort();
    else if (tb == d_ptr->openButton)
        d_ptr->locate();
    else if (tb == d_ptr->moveButton)
        d_ptr->move();
    else if (tb == d_ptr->viewButton)
        d_ptr->view();
}

void DownloadItem::showImagePreview(bool show)
{
   if (show) {
       const QString imagePath = d_ptr->localPathLabel->text();
       ImageViewer::instance()->view(imagePath);
   } else {
       ImageViewer::instance()->hide();
   }
}

} // namespace Jcr
